const axios = require('axios');
const crypto = require('crypto');
const config = require('../../config/config');
const { setupLogger } = require('../../utils/logger');

class OkxService {
  constructor() {
    this.logger = setupLogger();
    this.baseUrl = config.dataSources.okx.baseUrl;
    this.apiKey = config.dataSources.okx.apiKey;
    this.apiSecret = config.dataSources.okx.apiSecret;
    this.passphrase = config.dataSources.okx.passphrase;
  }

  async fetchData() {
    try {
      this.logger.info('开始获取OKX数据...');
      
      const data = [];
      
      // 获取交易对信息
      const instruments = await this.getInstruments();
      data.push(...instruments);
      
      // 获取24小时价格统计
      const tickers = await this.getTickers();
      data.push(...tickers);
      
      // 获取订单簿数据
      const orderBooks = await this.getOrderBooks(['BTC-USDT', 'ETH-USDT', 'OKB-USDT']);
      data.push(...orderBooks);
      
      // 获取最近成交记录
      const trades = await this.getRecentTrades(['BTC-USDT', 'ETH-USDT']);
      data.push(...trades);
      
      // 获取K线数据
      const candlesticks = await this.getCandlesticks(['BTC-USDT', 'ETH-USDT']);
      data.push(...candlesticks);
      
      this.logger.info(`OKX数据获取完成，共获取 ${data.length} 条数据`);
      return data;
    } catch (error) {
      this.logger.error('OKX数据获取失败:', error);
      return [];
    }
  }

  async getInstruments() {
    try {
      const response = await axios.get(`${this.baseUrl}/public/instruments`, {
        params: {
          instType: 'SPOT'
        }
      });
      
      if (response.data.code !== '0') {
        throw new Error(`OKX API错误: ${response.data.msg}`);
      }
      
      return response.data.data
        .slice(0, 50) // 限制数量
        .map(instrument => ({
          source: 'okx',
          type: 'instrument',
          instId: instrument.instId,
          baseCcy: instrument.baseCcy,
          quoteCcy: instrument.quoteCcy,
          minSz: parseFloat(instrument.minSz),
          lotSz: parseFloat(instrument.lotSz),
          tickSz: parseFloat(instrument.tickSz),
          state: instrument.state,
          timestamp: new Date().toISOString()
        }));
    } catch (error) {
      this.logger.error('获取OKX交易对信息失败:', error);
      return [];
    }
  }

  async getTickers() {
    try {
      const response = await axios.get(`${this.baseUrl}/public/tickers`, {
        params: {
          instType: 'SPOT'
        }
      });
      
      if (response.data.code !== '0') {
        throw new Error(`OKX API错误: ${response.data.msg}`);
      }
      
      return response.data.data
        .filter(ticker => parseFloat(ticker.vol24h) > 1000) // 过滤低交易量
        .slice(0, 100) // 限制数量
        .map(ticker => ({
          source: 'okx',
          type: 'ticker',
          instId: ticker.instId,
          last: parseFloat(ticker.last),
          lastSz: parseFloat(ticker.lastSz),
          askPx: parseFloat(ticker.askPx),
          askSz: parseFloat(ticker.askSz),
          bidPx: parseFloat(ticker.bidPx),
          bidSz: parseFloat(ticker.bidSz),
          open24h: parseFloat(ticker.open24h),
          high24h: parseFloat(ticker.high24h),
          low24h: parseFloat(ticker.low24h),
          vol24h: parseFloat(ticker.vol24h),
          volCcy24h: parseFloat(ticker.volCcy24h),
          sodUtc0: parseFloat(ticker.sodUtc0),
          sodUtc8: parseFloat(ticker.sodUtc8),
          ts: parseInt(ticker.ts),
          timestamp: new Date().toISOString()
        }));
    } catch (error) {
      this.logger.error('获取OKX价格统计失败:', error);
      return [];
    }
  }

  async getOrderBooks(instIds) {
    const data = [];
    
    for (const instId of instIds) {
      try {
        const response = await axios.get(`${this.baseUrl}/public/books`, {
          params: {
            instId: instId,
            sz: 20
          }
        });
        
        if (response.data.code !== '0') {
          this.logger.error(`获取 ${instId} 订单簿失败: ${response.data.msg}`);
          continue;
        }
        
        const bookData = response.data.data[0];
        if (bookData) {
          data.push({
            source: 'okx',
            type: 'order_book',
            instId: instId,
            bids: bookData.bids.map(bid => ({
              price: parseFloat(bid[0]),
              size: parseFloat(bid[1]),
              liquidatedOrders: parseInt(bid[2]),
              orderCount: parseInt(bid[3])
            })),
            asks: bookData.asks.map(ask => ({
              price: parseFloat(ask[0]),
              size: parseFloat(ask[1]),
              liquidatedOrders: parseInt(ask[2]),
              orderCount: parseInt(ask[3])
            })),
            ts: parseInt(bookData.ts),
            timestamp: new Date().toISOString()
          });
        }
        
        // 避免过快请求
        await this.delay(100);
      } catch (error) {
        this.logger.error(`获取 ${instId} 订单簿失败:`, error.message);
        continue;
      }
    }
    
    return data;
  }

  async getRecentTrades(instIds) {
    const data = [];
    
    for (const instId of instIds) {
      try {
        const response = await axios.get(`${this.baseUrl}/public/trades`, {
          params: {
            instId: instId,
            limit: 100
          }
        });
        
        if (response.data.code !== '0') {
          this.logger.error(`获取 ${instId} 成交记录失败: ${response.data.msg}`);
          continue;
        }
        
        const trades = response.data.data.map(trade => ({
          source: 'okx',
          type: 'trade',
          instId: instId,
          tradeId: trade.tradeId,
          px: parseFloat(trade.px),
          sz: parseFloat(trade.sz),
          side: trade.side,
          ts: parseInt(trade.ts),
          timestamp: new Date().toISOString()
        }));
        
        data.push(...trades);
        
        // 避免过快请求
        await this.delay(100);
      } catch (error) {
        this.logger.error(`获取 ${instId} 成交记录失败:`, error.message);
        continue;
      }
    }
    
    return data;
  }

  async getCandlesticks(instIds, bar = '1H', limit = 100) {
    const data = [];
    
    for (const instId of instIds) {
      try {
        const response = await axios.get(`${this.baseUrl}/public/candles`, {
          params: {
            instId: instId,
            bar: bar,
            limit: limit
          }
        });
        
        if (response.data.code !== '0') {
          this.logger.error(`获取 ${instId} K线数据失败: ${response.data.msg}`);
          continue;
        }
        
        const candles = response.data.data.map(candle => ({
          source: 'okx',
          type: 'candlestick',
          instId: instId,
          bar: bar,
          ts: parseInt(candle[0]),
          open: parseFloat(candle[1]),
          high: parseFloat(candle[2]),
          low: parseFloat(candle[3]),
          close: parseFloat(candle[4]),
          vol: parseFloat(candle[5]),
          volCcy: parseFloat(candle[6]),
          volCcyQuote: parseFloat(candle[7]),
          confirm: candle[8] === '1',
          timestamp: new Date().toISOString()
        }));
        
        data.push(...candles);
        
        // 避免过快请求
        await this.delay(100);
      } catch (error) {
        this.logger.error(`获取 ${instId} K线数据失败:`, error.message);
        continue;
      }
    }
    
    return data;
  }

  // 私有API方法（需要API密钥）
  async getAccountBalance() {
    if (!this.apiKey || !this.apiSecret || !this.passphrase) {
      this.logger.warn('OKX API密钥未配置，跳过账户余额获取');
      return null;
    }

    try {
      const timestamp = new Date().toISOString();
      const method = 'GET';
      const requestPath = '/api/v5/account/balance';
      const body = '';
      
      const signature = this.createSignature(timestamp, method, requestPath, body);
      
      const response = await axios.get(`${this.baseUrl}${requestPath}`, {
        headers: {
          'OK-ACCESS-KEY': this.apiKey,
          'OK-ACCESS-SIGN': signature,
          'OK-ACCESS-TIMESTAMP': timestamp,
          'OK-ACCESS-PASSPHRASE': this.passphrase,
          'Content-Type': 'application/json'
        }
      });
      
      if (response.data.code !== '0') {
        throw new Error(`OKX API错误: ${response.data.msg}`);
      }
      
      return {
        source: 'okx',
        type: 'account_balance',
        details: response.data.data[0]?.details?.map(detail => ({
          ccy: detail.ccy,
          bal: parseFloat(detail.bal),
          frozenBal: parseFloat(detail.frozenBal),
          availBal: parseFloat(detail.availBal)
        })) || [],
        timestamp: new Date().toISOString()
      };
    } catch (error) {
      this.logger.error('获取OKX账户余额失败:', error);
      return null;
    }
  }

  createSignature(timestamp, method, requestPath, body) {
    const message = timestamp + method + requestPath + body;
    return crypto.createHmac('sha256', this.apiSecret).update(message).digest('base64');
  }

  delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
}

module.exports = new OkxService();

